#include <g-bios.h>
#include <flash/flash.h>
#include <flash/nand.h>
#include <arch/at91sam926x.h>


static void AT91NandCmdCtrl(struct NandFlash *pNandFlash, int nCmd, unsigned int nCtrl)
{
	struct NandCtrl *pNandCtrl;

	if (nCmd == NAND_CMMD_NONE)
		return;

	pNandCtrl = pNandFlash->pMaster;

	if (nCtrl & NAND_CLE)
		writeb(nCmd, (char *)pNandCtrl->pWriteDataAddr + NAND_CMMD);
	else
		writeb(nCmd, (char *)pNandCtrl->pWriteDataAddr + NAND_ADDR);
}


static int AT91NandReady(struct NandFlash *pNandFlash)
{
	return ReadLong(AT91SAM926X_PA_PIOA + PIO_PDSR) & PIO_NAND_RDY;
}


static __INIT__ int AT91NandProbe(void)
{
	int ret;
	struct NandCtrl *pNandCtrl;


	DRIVER_INFO("AT91 Nand Driver.\n");

	pNandCtrl = GkNandCtrlNew();

	if (NULL == pNandCtrl)
		return -ENOMEM;

	pNandCtrl->pReadDataAddr  = (void *)AT91SAM926X_PA_NAND;
	pNandCtrl->pWriteDataAddr = (void *)AT91SAM926X_PA_NAND;

	strcpy(pNandCtrl->szNcName, "atmel_nand");

	pNandCtrl->CmdCtrl  = AT91NandCmdCtrl;
	pNandCtrl->FlashIsReady = AT91NandReady;

	// GkNandSetEccMode(pNandCtrl, NAND_ECC_SW); // fixme: NAND_ECC_HW

	ret = GkNandCtrlRegister(pNandCtrl);
	if (ret < 0) 
	{
		ret = -ENODEV;
		goto L1;
	}

	return 0;

L1:
	kfree(pNandCtrl);

	return ret;
}

DRIVER_INIT(AT91NandProbe);
